home *** CD-ROM | disk | FTP | other *** search
/ PC World Komputer 2007 December / PCWKCD1207B.iso / Blogowanie poza sfera / Flock 0.9.1.3 stable / flock-0.9.1.3.en-US.win32.exe / flock / chrome / browser.jar / content / browser / preferences / downloadactions.js < prev    next >
Text File  |  2006-09-22  |  31KB  |  825 lines

  1. //@line 38 "/cygdrive/K/tinderbuild/src/flock/mozilla/browser/components/preferences/downloadactions.js"
  2.  
  3. const kPluginHandlerContractID = "@mozilla.org/content/plugin/document-loader-factory;1";
  4. const kDisabledPluginTypesPref = "plugin.disable_full_page_plugin_for_types";
  5. const kShowPluginsInList = "browser.download.show_plugins_in_list";
  6. const kHideTypesWithoutExtensions = "browser.download.hide_plugins_without_extensions";
  7. const kRootTypePrefix = "urn:mimetype:";
  8.  
  9. ///////////////////////////////////////////////////////////////////////////////
  10. // MIME Types Datasource RDF Utils
  11. function NC_URI(aProperty)
  12. {
  13.   return "http://home.netscape.com/NC-rdf#" + aProperty;
  14. }
  15.  
  16. function MIME_URI(aType)
  17. {
  18.   return "urn:mimetype:" + aType;
  19. }
  20.  
  21. function HANDLER_URI(aHandler)
  22. {
  23.   return "urn:mimetype:handler:" + aHandler;
  24. }
  25.  
  26. function APP_URI(aType)
  27. {
  28.   return "urn:mimetype:externalApplication:" + aType;
  29. }
  30.  
  31. var gDownloadActionsWindow = {  
  32.   _tree         : null,
  33.   _editButton   : null,
  34.   _removeButton : null,
  35.   _actions      : [],
  36.   _plugins      : {},
  37.   _bundle       : null,
  38.   _pref         : Components.classes["@mozilla.org/preferences-service;1"]
  39.                             .getService(Components.interfaces.nsIPrefBranch),
  40.   _mimeSvc      : Components.classes["@mozilla.org/uriloader/external-helper-app-service;1"]
  41.                             .getService(Components.interfaces.nsIMIMEService),
  42.   _excludingPlugins           : false,
  43.   _excludingMissingExtensions : false,
  44.   
  45.   init: function ()
  46.   {
  47.     (this._editButton = document.getElementById("editFileHandler")).disabled = true;
  48.     (this._removeButton = document.getElementById("removeFileHandler")).disabled = true;    
  49.  
  50.     if (this._pref instanceof Components.interfaces.nsIPrefBranchInternal) {
  51.       this._pref.addObserver(kShowPluginsInList, this, false);
  52.       this._pref.addObserver(kHideTypesWithoutExtensions, this, false);
  53.     }
  54.     
  55.     // Initialize the File Type list
  56.     this._bundle = document.getElementById("bundlePreferences");
  57.     this._tree = document.getElementById("fileHandlersList");
  58.     this._loadView();
  59.     // Determine any exclusions being applied - e.g. don't show types for which
  60.     // only a plugin handler exists, don't show types lacking extensions, etc. 
  61.     this._view._rowCount = this._updateExclusions();    
  62.     this._tree.treeBoxObject.view = this._view;  
  63.  
  64.     var indexToSelect = parseInt(this._tree.getAttribute("lastSelected"));
  65.     if (indexToSelect < this._tree.view.rowCount)
  66.       this._tree.view.selection.select(indexToSelect);
  67.     this._tree.focus();    
  68.   },
  69.   
  70.   _loadView: function ()
  71.   {
  72.     // Reset ALL the collections and state flags, because we can call this after
  73.     // the window has initially displayed by resetting the filter. 
  74.     this._actions = [];
  75.     this._plugins = {};
  76.     this._view._filtered = false;
  77.     this._view._filterSet = [];
  78.     this._view._usingExclusionSet = false;
  79.     this._view._exclusionSet = [];
  80.     this._view._filterValue = "";
  81.  
  82.     this._loadPluginData();
  83.     this._loadMIMERegistryData();
  84.   },
  85.   
  86.   _updateRowCount: function (aNewRowCount)
  87.   {
  88.     var oldCount = this._view._rowCount;
  89.     this._view._rowCount = 0;
  90.     this._tree.treeBoxObject.rowCountChanged(0, -oldCount);
  91.     this._view._rowCount = aNewRowCount;
  92.     this._tree.treeBoxObject.rowCountChanged(0, aNewRowCount);
  93.   },
  94.   
  95.   uninit: function ()
  96.   {
  97.     if (this._pref instanceof Components.interfaces.nsIPrefBranchInternal) {
  98.       this._pref.removeObserver(kShowPluginsInList, this);
  99.       this._pref.removeObserver(kHideTypesWithoutExtensions, this);
  100.     }
  101.   },
  102.   
  103.   observe: function (aSubject, aTopic, aData)
  104.   {
  105.     if (aTopic == "nsPref:changed" &&
  106.         (aData == kShowPluginsInList || aData == kHideTypesWithoutExtensions))
  107.       this._updateRowCount(this._updateExclusions());
  108.   },
  109.   
  110.   _updateExclusions: function ()
  111.   {
  112.     this._excludingPlugins = !this._pref.getBoolPref(kShowPluginsInList);
  113.     this._excludingMissingExtensions = this._pref.getBoolPref(kHideTypesWithoutExtensions);    
  114.     this._view._exclusionSet = [].concat(this._actions);
  115.     if (this._excludingMissingExtensions) {
  116.       this._view._usingExclusionSet = true;
  117.       for (var i = 0; i < this._view._exclusionSet.length;) {
  118.         if (!this._view._exclusionSet[i].hasExtension)
  119.           this._view._exclusionSet.splice(i, 1);
  120.         else
  121.           ++i;
  122.       }
  123.     }
  124.     if (this._excludingPlugins) {
  125.       this._view._usingExclusionSet = true;
  126.       for (i = 0; i < this._view._exclusionSet.length;) {
  127.         if (this._view._exclusionSet[i].handledOnlyByPlugin)
  128.           this._view._exclusionSet.splice(i, 1);
  129.         else
  130.           ++i        
  131.       }      
  132.     }
  133.  
  134.     return this._view._usingExclusionSet ? this._view._exclusionSet.length 
  135.                                          : this._view._filtered ? this._view._filterSet.length 
  136.                                                                 : this._actions.length;
  137.   },
  138.   
  139.   _loadPluginData: function ()
  140.   {
  141.     // Read enabled plugin type information from the category manager
  142.     var disabled = "";
  143.     if (this._pref.prefHasUserValue(kDisabledPluginTypesPref)) 
  144.       disabled = this._pref.getCharPref(kDisabledPluginTypesPref);
  145.     
  146.     for (var i = 0; i < navigator.plugins.length; ++i) {
  147.       var plugin = navigator.plugins[i];
  148.       for (var j = 0; j < plugin.length; ++j) {
  149.         var actionName = this._bundle.getFormattedString("openWith", [plugin.name])
  150.         var type = plugin[j].type;
  151.         this._createAction(type, actionName, true, FILEACTION_OPEN_PLUGIN, 
  152.                            null, true, disabled.indexOf(type) == -1, true);
  153.       }
  154.     }
  155.   },
  156.  
  157.   _createAction: function (aMIMEType, aActionName, 
  158.                            aIsEditable, aHandleMode, aCustomHandler,
  159.                            aPluginAvailable, aPluginEnabled, 
  160.                            aHandledOnlyByPlugin)
  161.   {
  162.     var newAction = !(aMIMEType in this._plugins);
  163.     var action = newAction ? new FileAction() : this._plugins[aMIMEType];
  164.     action.type = aMIMEType;
  165.     var info = this._mimeSvc.getFromTypeAndExtension(action.type, null);
  166.     
  167.     // File Extension
  168.     try {
  169.       action.extension = info.primaryExtension;
  170.     }
  171.     catch (e) {
  172.       action.extension = this._bundle.getString("extensionNone");
  173.       action.hasExtension = false;
  174.     }
  175.     
  176.     // Large and Small Icon
  177.     try {
  178.       action.smallIcon = "moz-icon://goat." + info.primaryExtension + "?size=16";
  179.       action.bigIcon = "moz-icon://goat." + info.primaryExtension + "?size=32";
  180.     }
  181.     catch (e) {
  182.       action.smallIcon = "moz-icon://goat?size=16&contentType=" + info.MIMEType;
  183.       action.bigIcon = "moz-icon://goat?contentType=" + info.MIMEType + "&size=32";
  184.     }
  185.  
  186.     // Pretty Type Name
  187.     if (info.description == "") {
  188.       try {
  189.         action.typeName = this._bundle.getFormattedString("fileEnding", [info.primaryExtension.toUpperCase()]);
  190.       }
  191.       catch (e) { 
  192.         // Wow, this sucks, just show the MIME type as a last ditch effort to display
  193.         // the type of file that this is. 
  194.         action.typeName = info.MIMEType;
  195.       }
  196.     }
  197.     else
  198.       action.typeName = info.description;
  199.  
  200.     // Pretty Action Name
  201.     if (aActionName)
  202.       action.action         = aActionName;
  203.     action.pluginAvailable  = aPluginAvailable;
  204.     action.pluginEnabled    = aPluginEnabled;
  205.     action.editable         = aIsEditable;
  206.     action.handleMode       = aHandleMode;
  207.     action.customHandler    = aCustomHandler;
  208.     action.mimeInfo         = info;
  209.     action.handledOnlyByPlugin  = aHandledOnlyByPlugin
  210.     
  211.     if (newAction && !(action.handledOnlyByPlugin && !action.pluginEnabled)) {
  212.       this._actions.push(action);
  213.       this._plugins[action.type] = action;
  214.     }      
  215.     return action;
  216.   },
  217.   
  218.   _loadMIMEDS: function ()
  219.   {
  220.     var fileLocator = Components.classes["@mozilla.org/file/directory_service;1"]
  221.                                 .getService(Components.interfaces.nsIProperties);
  222.     
  223.     var file = fileLocator.get("UMimTyp", Components.interfaces.nsIFile);
  224.  
  225.     var ioService = Components.classes["@mozilla.org/network/io-service;1"]
  226.                               .getService(Components.interfaces.nsIIOService);
  227.     var fileHandler = ioService.getProtocolHandler("file")
  228.                                .QueryInterface(Components.interfaces.nsIFileProtocolHandler);
  229.     this._mimeDS = this._rdf.GetDataSourceBlocking(fileHandler.getURLSpecFromFile(file));
  230.   },
  231.   
  232.   _getLiteralValue: function (aResource, aProperty)
  233.   {
  234.     var property = this._rdf.GetResource(NC_URI(aProperty));
  235.     var value = this._mimeDS.GetTarget(aResource, property, true);
  236.     if (value)
  237.       return value.QueryInterface(Components.interfaces.nsIRDFLiteral).Value;
  238.     return "";
  239.   },
  240.   
  241.   _getChildResource: function (aResource, aProperty)
  242.   {
  243.     var property = this._rdf.GetResource(NC_URI(aProperty));
  244.     return this._mimeDS.GetTarget(aResource, property, true);
  245.   },
  246.   
  247.   _getDisplayNameForFile: function (aFile)
  248.   {
  249. //@line 286 "/cygdrive/K/tinderbuild/src/flock/mozilla/browser/components/preferences/downloadactions.js"
  250.     if (aFile instanceof Components.interfaces.nsILocalFileWin) {
  251.       try {
  252.         return aFile.getVersionInfoField("FileDescription"); 
  253.       }
  254.       catch (e) {
  255.         // fall through to the filename
  256.       }
  257.     }
  258. //@line 304 "/cygdrive/K/tinderbuild/src/flock/mozilla/browser/components/preferences/downloadactions.js"
  259.     var ios = Components.classes["@mozilla.org/network/io-service;1"]
  260.                         .getService(Components.interfaces.nsIIOService);
  261.     var url = ios.newFileURI(aFile).QueryInterface(Components.interfaces.nsIURL);
  262.     return url.fileName;
  263.   },  
  264.   
  265.   _loadMIMERegistryData: function ()
  266.   {
  267.     this._rdf = Components.classes["@mozilla.org/rdf/rdf-service;1"]
  268.                           .getService(Components.interfaces.nsIRDFService);
  269.     this._loadMIMEDS();                          
  270.                           
  271.     var root = this._rdf.GetResource("urn:mimetypes:root");
  272.     var container = Components.classes["@mozilla.org/rdf/container;1"]
  273.                               .createInstance(Components.interfaces.nsIRDFContainer);
  274.     container.Init(this._mimeDS, root);
  275.     
  276.     var elements = container.GetElements();
  277.     while (elements.hasMoreElements()) {
  278.       var type = elements.getNext();
  279.       if (!(type instanceof Components.interfaces.nsIRDFResource))
  280.         break;
  281.       var editable = this._getLiteralValue(type, "editable") == "true";
  282.       if (!editable)
  283.         continue;
  284.       
  285.       var handler = this._getChildResource(type, "handlerProp");
  286.       var alwaysAsk = this._getLiteralValue(handler, "alwaysAsk") == "true";
  287.       if (alwaysAsk)
  288.         continue;
  289.       var saveToDisk        = this._getLiteralValue(handler, "saveToDisk") == "true";
  290.       var useSystemDefault  = this._getLiteralValue(handler, "useSystemDefault") == "true";
  291.       var editable          = this._getLiteralValue(type, "editable") == "true";
  292.       var handledInternally = this._getLiteralValue(handler, "handleInternal") == "true";
  293.       var externalApp       = this._getChildResource(handler, "externalApplication");
  294.       var externalAppPath   = this._getLiteralValue(externalApp, "path");
  295.       try {
  296.         var customHandler = Components.classes["@mozilla.org/file/local;1"]
  297.                                       .createInstance(Components.interfaces.nsILocalFile);
  298.         customHandler.initWithPath(externalAppPath);
  299.       }
  300.       catch (e) {
  301.         customHandler = null;
  302.       }      
  303.       if (customHandler && !customHandler.exists())
  304.         customHandler = null;
  305.       var mimeType = this._getLiteralValue(type, "value");
  306.       var typeInfo = this._mimeSvc.getFromTypeAndExtension(mimeType, null);
  307.  
  308.       // Determine the pretty name of the associated action.
  309.       var actionName = "";
  310.       var handleMode = 0;
  311.       if (saveToDisk) {
  312.         // Save the file to disk
  313.         actionName = this._bundle.getString("saveToDisk");
  314.         handleMode = FILEACTION_SAVE_TO_DISK;
  315.       }
  316.       else if (useSystemDefault) {
  317.         // Use the System Default handler
  318.         actionName = this._bundle.getFormattedString("openWith", 
  319.                                                      [typeInfo.defaultDescription]);
  320.         handleMode = FILEACTION_OPEN_DEFAULT;
  321.       }
  322.       else {
  323.         // Custom Handler
  324.         if (customHandler) {
  325.           actionName = this._bundle.getFormattedString("openWith", 
  326.                                                        [this._getDisplayNameForFile(customHandler)]);
  327.           handleMode = FILEACTION_OPEN_CUSTOM;
  328.         }
  329.         else {
  330.           // Corrupt datasource, invalid custom handler path. Revert to default.
  331.           actionName = this._bundle.getFormattedString("openWith", 
  332.                                                        [typeInfo.defaultDescription]);
  333.           handleMode = FILEACTION_OPEN_DEFAULT;
  334.         }
  335.       }
  336.  
  337.       if (handledInternally)
  338.         handleMode = FILEACTION_OPEN_INTERNALLY;
  339.       
  340.       var pluginAvailable = mimeType in this._plugins && this._plugins[mimeType].pluginAvailable;
  341.       var pluginEnabled = pluginAvailable && this._plugins[mimeType].pluginEnabled;
  342.       if (pluginEnabled) {
  343.         handleMode = FILEACTION_OPEN_PLUGIN;
  344.         actionName = null;
  345.       }
  346.       var action = this._createAction(mimeType, actionName, editable, handleMode, 
  347.                                       customHandler, pluginAvailable, pluginEnabled,
  348.                                       false);
  349.     }
  350.   },
  351.   
  352.   _view: {
  353.     _filtered           : false,
  354.     _filterSet          : [],
  355.     _usingExclusionSet  : false,
  356.     _exclusionSet       : [],
  357.     _filterValue        : "",
  358.  
  359.     _rowCount: 0,
  360.     get rowCount() 
  361.     { 
  362.       return this._rowCount; 
  363.     },
  364.     
  365.     get activeCollection ()
  366.     {
  367.       return this._filtered ? this._filterSet 
  368.                             : this._usingExclusionSet ? this._exclusionSet 
  369.                                                       : gDownloadActionsWindow._actions;
  370.     },
  371.  
  372.     getItemAtIndex: function (aIndex)
  373.     {
  374.       return this.activeCollection[aIndex];
  375.     },
  376.     
  377.     getCellText: function (aIndex, aColumn)
  378.     {
  379.       switch (aColumn.id) {
  380.       case "fileExtension":
  381.         return this.getItemAtIndex(aIndex).extension.toUpperCase();
  382.       case "fileType":
  383.         return this.getItemAtIndex(aIndex).typeName;
  384.       case "fileMIMEType":
  385.         return this.getItemAtIndex(aIndex).type;
  386.       case "fileHandler":
  387.         return this.getItemAtIndex(aIndex).action;
  388.       }
  389.       return "";
  390.     },
  391.     getImageSrc: function (aIndex, aColumn) 
  392.     {
  393.       if (aColumn.id == "fileExtension") 
  394.         return this.getItemAtIndex(aIndex).smallIcon;
  395.       return "";
  396.     },
  397.     _selection: null, 
  398.     get selection () { return this._selection; },
  399.     set selection (val) { this._selection = val; return val; },
  400.     getRowProperties: function (aIndex, aProperties) {},
  401.     getCellProperties: function (aIndex, aColumn, aProperties) {},
  402.     getColumnProperties: function (aColumn, aProperties) {},
  403.     isContainer: function (aIndex) { return false; },
  404.     isContainerOpen: function (aIndex) { return false; },
  405.     isContainerEmpty: function (aIndex) { return false; },
  406.     isSeparator: function (aIndex) { return false; },
  407.     isSorted: function (aIndex) { return false; },
  408.     canDrop: function (aIndex, aOrientation) { return false; },
  409.     drop: function (aIndex, aOrientation) {},
  410.     getParentIndex: function (aIndex) { return -1; },
  411.     hasNextSibling: function (aParentIndex, aIndex) { return false; },
  412.     getLevel: function (aIndex) { return 0; },
  413.     getProgressMode: function (aIndex, aColumn) {},    
  414.     getCellValue: function (aIndex, aColumn) {},
  415.     setTree: function (aTree) {},    
  416.     toggleOpenState: function (aIndex) { },
  417.     cycleHeader: function (aColumn) {},    
  418.     selectionChanged: function () {},    
  419.     cycleCell: function (aIndex, aColumn) {},    
  420.     isEditable: function (aIndex, aColumn) { return false; },
  421.     setCellValue: function (aIndex, aColumn, aValue) {},    
  422.     setCellText: function (aIndex, aColumn, aValue) {},    
  423.     performAction: function (aAction) {},  
  424.     performActionOnRow: function (aAction, aIndex) {},    
  425.     performActionOnCell: function (aAction, aindex, aColumn) {}
  426.   },
  427.  
  428.   removeFileHandler: function ()
  429.   {
  430.     var selection = this._tree.view.selection; 
  431.     if (selection.count < 1)
  432.       return;
  433.       
  434.     var promptService = Components.classes["@mozilla.org/embedcomp/prompt-service;1"]
  435.                                   .getService(Components.interfaces.nsIPromptService);
  436.     var flags = promptService.BUTTON_TITLE_IS_STRING * promptService.BUTTON_POS_0;
  437.     flags += promptService.BUTTON_TITLE_CANCEL * promptService.BUTTON_POS_1;
  438.  
  439.     var title = this._bundle.getString("removeTitle" + (selection.count > 1 ? "Multiple" : "Single"));
  440.     var message = this._bundle.getString("removeMessage" + (selection.count > 1 ? "Multiple" : "Single"));
  441.     var button = this._bundle.getString("removeButton" + (selection.count > 1 ? "Multiple" : "Single"));
  442.     var rv = promptService.confirmEx(window, title, message, flags, button, 
  443.                                      null, null, null, { value: 0 });
  444.     if (rv != 0)
  445.       return;     
  446.  
  447.     var rangeCount = selection.getRangeCount();
  448.     var lastSelected = 0;
  449.     var mimeDSDirty = false;
  450.     for (var i = 0; i < rangeCount; ++i) {
  451.       var min = { }; var max = { };
  452.       selection.getRangeAt(i, min, max);
  453.       for (var j = min.value; j <= max.value; ++j) {
  454.         var item = this._view.getItemAtIndex(j);
  455.         if (!item.handledOnlyByPlugin) {
  456.           // There is data for this type in the MIME registry, so make sure we
  457.           // remove it from the MIME registry. We don't disable the plugin here because
  458.           // if we do there's currently no way through the UI to re-enable it. We may
  459.           // come up with some sort of solution for that at a later date. 
  460.           var typeRes = this._rdf.GetResource(MIME_URI(item.type));
  461.           var handlerRes = this._getChildResource(typeRes, "handlerProp");
  462.           var extAppRes = this._getChildResource(handlerRes, "externalApplication");
  463.           this._cleanResource(extAppRes);
  464.           this._cleanResource(handlerRes);
  465.           this._cleanResource(typeRes); 
  466.           mimeDSDirty = true;         
  467.         }
  468.         lastSelected = (j + 1) >= this._view.rowCount ? j-1 : j;
  469.       }
  470.     }
  471.     if (mimeDSDirty && 
  472.         this._mimeDS instanceof Components.interfaces.nsIRDFRemoteDataSource)
  473.       this._mimeDS.Flush();
  474.     
  475.     // Just reload the list to make sure deletions are respected
  476.     this._loadView();
  477.     this._updateRowCount(this._updateExclusions());
  478.  
  479.     selection.select(lastSelected);
  480.   },
  481.   
  482.   _cleanResource: function (aResource)
  483.   {
  484.     var labels = this._mimeDS.ArcLabelsOut(aResource);
  485.     while (labels.hasMoreElements()) {
  486.       var arc = labels.getNext();
  487.       if (!(arc instanceof Components.interfaces.nsIRDFResource))
  488.         break;
  489.       var target = this._mimeDS.GetTarget(aResource, arc, true);
  490.       this._mimeDS.Unassert(aResource, arc, target);
  491.     }
  492.   },
  493.   
  494.   _disablePluginForItem: function (aItem)
  495.   {
  496.     if (aItem.pluginAvailable) {
  497.       // Since we're disabling the full page plugin for this content type, 
  498.       // we must add it to the disabled list if it's not in there already.
  499.       var prefs = Components.classes["@mozilla.org/preferences-service;1"]
  500.                             .getService(Components.interfaces.nsIPrefBranch);
  501.       var disabled = aItem.type;
  502.       if (prefs.prefHasUserValue(kDisabledPluginTypesPref)) {
  503.         disabled = prefs.getCharPref(kDisabledPluginTypesPref);
  504.         if (disabled.indexOf(aItem.type) == -1) 
  505.           disabled += "," + aItem.type;
  506.       }
  507.       prefs.setCharPref(kDisabledPluginTypesPref, disabled);   
  508.       
  509.       // Also, we update the category manager so that existing browser windows
  510.       // update.
  511.       var catman = Components.classes["@mozilla.org/categorymanager;1"]
  512.                              .getService(Components.interfaces.nsICategoryManager);
  513.       catman.deleteCategoryEntry("Gecko-Content-Viewers", aItem.type, false);     
  514.     }    
  515.   },
  516.   
  517.   _enablePluginForItem: function (aItem)
  518.   {
  519.     var prefs = Components.classes["@mozilla.org/preferences-service;1"]
  520.                           .getService(Components.interfaces.nsIPrefBranch);
  521.     // Since we're enabling the full page plugin for this content type, we must
  522.     // look at the disabled types list and ensure that this type isn't in it.
  523.     if (prefs.prefHasUserValue(kDisabledPluginTypesPref)) {
  524.       var disabledList = prefs.getCharPref(kDisabledPluginTypesPref);
  525.       if (disabledList == aItem.type)
  526.         prefs.clearUserPref(kDisabledPluginTypesPref);
  527.       else {
  528.         var disabledTypes = disabledList.split(",");
  529.         var disabled = "";
  530.         for (var i = 0; i < disabledTypes.length; ++i) {
  531.           if (aItem.type != disabledTypes[i])
  532.             disabled += disabledTypes[i] + (i == disabledTypes.length - 1 ? "" : ",");
  533.         }
  534.         prefs.setCharPref(kDisabledPluginTypesPref, disabled);
  535.       }
  536.     }
  537.  
  538.     // Also, we update the category manager so that existing browser windows
  539.     // update.
  540.     var catman = Components.classes["@mozilla.org/categorymanager;1"]
  541.                            .getService(Components.interfaces.nsICategoryManager);
  542.     catman.addCategoryEntry("Gecko-Content-Viewers", aItem.type,
  543.                             kPluginHandlerContractID, false, true);
  544.   },
  545.   
  546.   _ensureMIMERegistryEntry: function (aItem)
  547.   {
  548.     var root = this._rdf.GetResource("urn:mimetypes:root");
  549.     var container = Components.classes["@mozilla.org/rdf/container;1"]
  550.                               .createInstance(Components.interfaces.nsIRDFContainer);
  551.     container.Init(this._mimeDS, root);
  552.     
  553.     var itemResource = this._rdf.GetResource(MIME_URI(aItem.type));
  554.     var handlerResource = null;
  555.     if (container.IndexOf(itemResource) == -1) {
  556.       container.AppendElement(itemResource);
  557.       this._setLiteralValue(itemResource, "editable", "true");
  558.       this._setLiteralValue(itemResource, "value", aItem.type);
  559.       
  560.       handlerResource = this._rdf.GetResource(HANDLER_URI(aItem.type));
  561.       this._setLiteralValue(handlerResource, "alwaysAsk", "false");
  562.       var handlerProp = this._rdf.GetResource(NC_URI("handlerProp"));
  563.       this._mimeDS.Assert(itemResource, handlerProp, handlerResource, true);
  564.       
  565.       var extAppResource = this._rdf.GetResource(APP_URI(aItem.type));
  566.       this._setLiteralValue(extAppResource, "path", "");
  567.       var extAppProp = this._rdf.GetResource(NC_URI("externalApplication"));
  568.       this._mimeDS.Assert(handlerResource, extAppProp, extAppResource, true);
  569.     }
  570.     else
  571.       handlerResource = this._getChildResource(itemResource, "handlerProp");
  572.         
  573.     return handlerResource;
  574.   },
  575.   
  576.   _setLiteralValue: function (aResource, aProperty, aValue)
  577.   {
  578.     var property = this._rdf.GetResource(NC_URI(aProperty));
  579.     var newValue = this._rdf.GetLiteral(aValue);
  580.     var oldValue = this._mimeDS.GetTarget(aResource, property, true);
  581.     if (oldValue)
  582.       this._mimeDS.Change(aResource, property, oldValue, newValue);
  583.     else
  584.       this._mimeDS.Assert(aResource, property, newValue, true);
  585.   },
  586.   
  587.   editFileHandler: function ()
  588.   {
  589.     var selection = this._tree.view.selection; 
  590.     if (selection.count != 1)
  591.       return;
  592.  
  593.     var item = this._view.getItemAtIndex(selection.currentIndex);
  594.     openDialog("chrome://browser/content/preferences/changeaction.xul", 
  595.                "_blank", "modal,centerscreen", item);
  596.     
  597.     // Update the database
  598.     switch (item.handleMode) {
  599.     case FILEACTION_OPEN_PLUGIN:
  600.       this._enablePluginForItem(item);
  601.       // We don't need to adjust the database because plugin settings always
  602.       // supercede whatever is in the db, leaving it untouched allows the last
  603.       // user setting(s) to be preserved if they ever revert.
  604.       break;
  605.     case FILEACTION_OPEN_DEFAULT:
  606.       this._disablePluginForItem(item);
  607.       var handlerRes = this._ensureMIMERegistryEntry(item);
  608.       this._setLiteralValue(handlerRes, "useSystemDefault", "true");
  609.       this._setLiteralValue(handlerRes, "saveToDisk", "false");
  610.       break;
  611.     case FILEACTION_OPEN_CUSTOM:
  612.       this._disablePluginForItem(item);
  613.       var handlerRes = this._ensureMIMERegistryEntry(item);
  614.       this._setLiteralValue(handlerRes, "useSystemDefault", "false");
  615.       this._setLiteralValue(handlerRes, "saveToDisk", "false");
  616.       var extAppRes = this._getChildResource(handlerRes, "externalApplication");
  617.       this._setLiteralValue(extAppRes, "path", item.customHandler.path);
  618.       break;
  619.     case FILEACTION_SAVE_TO_DISK:
  620.       this._disablePluginForItem(item);
  621.       var handlerRes = this._ensureMIMERegistryEntry(item);
  622.       this._setLiteralValue(handlerRes, "useSystemDefault", "false");
  623.       this._setLiteralValue(handlerRes, "saveToDisk", "true");
  624.       break;
  625.     }
  626.     
  627.     if (this._mimeDS instanceof Components.interfaces.nsIRDFRemoteDataSource)
  628.       this._mimeDS.Flush();
  629.     
  630.     // Update the view
  631.     this._tree.treeBoxObject.invalidateRow(selection.currentIndex);    
  632.   },
  633.   
  634.   onSelectionChanged: function ()
  635.   {
  636.     if (this._tree.view.rowCount == 0) {
  637.       this._removeButton.disabled = true;
  638.       this._editButton.disabled = true;
  639.       return;
  640.     }
  641.       
  642.     var selection = this._tree.view.selection; 
  643.     var selected = selection.count;
  644.     this._removeButton.disabled = selected == 0;
  645.     this._editButton.disabled = selected != 1;
  646.     var stringKey = selected > 1 ? "removeButtonMultiple" : "removeButtonSingle";
  647.     this._removeButton.label = this._bundle.getString(stringKey);
  648.     
  649.     var canRemove = true;
  650.     var canEdit = true;
  651.     
  652.     var rangeCount = selection.getRangeCount();
  653.     var min = { }, max = { };
  654.     var setLastSelected = false;
  655.     for (var i = 0; i < rangeCount; ++i) {
  656.       selection.getRangeAt(i, min, max);
  657.       
  658.       for (var j = min.value; j <= max.value; ++j) {
  659.         if (!setLastSelected) {
  660.           // Set the last selected index to the first item in the selection
  661.           this._tree.setAttribute("lastSelected", j);
  662.           setLastSelected = true;
  663.         }
  664.  
  665.         var item = this._view.getItemAtIndex(j);
  666.         if (item && 
  667.             (!item.editable || item.handleMode == FILEACTION_OPEN_INTERNALLY))
  668.           canEdit = false;
  669.         
  670.         if (item && 
  671.             (!item.editable || item.handleMode == FILEACTION_OPEN_INTERNALLY ||
  672.              item.handledOnlyByPlugin))
  673.           canRemove = false;
  674.       }
  675.     }
  676.     
  677.     if (!canRemove)
  678.       this._removeButton.disabled = true;
  679.     if (!canEdit)
  680.       this._editButton.disabled = true;
  681.   },
  682.   
  683.   _lastSortProperty : "",
  684.   _lastSortAscending: false,
  685.   sort: function (aProperty) 
  686.   {
  687.     var ascending = (aProperty == this._lastSortProperty) ? !this._lastSortAscending : true;
  688.     function sortByProperty(a, b) 
  689.     {
  690.       return a[aProperty].toLowerCase().localeCompare(b[aProperty].toLowerCase());
  691.     }
  692.     function sortByExtension(a, b)
  693.     {
  694.       if (!a.hasExtension && b.hasExtension)
  695.         return 1;
  696.       if (!b.hasExtension && a.hasExtension)
  697.         return -1;
  698.       return a.extension.toLowerCase().localeCompare(b.extension.toLowerCase());
  699.     }
  700.     // Sort the Filtered List, if in Filtered mode
  701.     if (!this._view._filtered) { 
  702.       this._view.activeCollection.sort(aProperty == "extension" ? sortByExtension : sortByProperty);
  703.       if (!ascending)
  704.         this._view.activeCollection.reverse();
  705.     }
  706.  
  707.     this._view.selection.clearSelection();
  708.     this._view.selection.select(0);
  709.     this._tree.treeBoxObject.invalidate();
  710.     this._tree.treeBoxObject.ensureRowIsVisible(0);
  711.  
  712.     this._lastSortAscending = ascending;
  713.     this._lastSortProperty = aProperty;
  714.   },
  715.   
  716.   clearFilter: function ()
  717.   {    
  718.     // Clear the Filter and the Tree Display
  719.     document.getElementById("filter").value = "";
  720.     this._view._filtered = false;
  721.     this._view._filterSet = [];
  722.  
  723.     // Just reload the list to make sure deletions are respected
  724.     this._loadView();
  725.     this._updateRowCount(this._updateExclusions());
  726.  
  727.     // Restore selection
  728.     this._view.selection.clearSelection();
  729.     for (var i = 0; i < this._lastSelectedRanges.length; ++i) {
  730.       var range = this._lastSelectedRanges[i];
  731.       this._view.selection.rangedSelect(range.min, range.max, true);
  732.     }
  733.     this._lastSelectedRanges = [];
  734.  
  735.     document.getElementById("actionsIntro").value = this._bundle.getString("actionsAll");
  736.     document.getElementById("clearFilter").disabled = true;
  737.     document.getElementById("filter").focus();
  738.   },
  739.   
  740.   _actionMatchesFilter: function (aAction)
  741.   {
  742.     return aAction.extension.toLowerCase().indexOf(this._view._filterValue) != -1 ||
  743.            aAction.typeName.toLowerCase().indexOf(this._view._filterValue) != -1 || 
  744.            aAction.type.toLowerCase().indexOf(this._view._filterValue) != -1 ||
  745.            aAction.action.toLowerCase().indexOf(this._view._filterValue) != -1;
  746.   },
  747.   
  748.   _filterActions: function (aFilterValue)
  749.   {
  750.     this._view._filterValue = aFilterValue;
  751.     var actions = [];
  752.     var collection = this._view._usingExclusionSet ? this._view._exclusionSet : this._actions;
  753.     for (var i = 0; i < collection.length; ++i) {
  754.       var action = collection[i];
  755.       if (this._actionMatchesFilter(action)) 
  756.         actions.push(action);
  757.     }
  758.     return actions;
  759.   },
  760.   
  761.   _lastSelectedRanges: [],
  762.   _saveState: function ()
  763.   {
  764.     // Save selection
  765.     var seln = this._view.selection;
  766.     this._lastSelectedRanges = [];
  767.     var rangeCount = seln.getRangeCount();
  768.     for (var i = 0; i < rangeCount; ++i) {
  769.       var min = {}; var max = {};
  770.       seln.getRangeAt(i, min, max);
  771.       this._lastSelectedRanges.push({ min: min.value, max: max.value });
  772.     }
  773.   },
  774.   
  775.   _filterTimeout: -1,
  776.   onFilterInput: function ()
  777.   {
  778.     if (this._filterTimeout != -1)
  779.       clearTimeout(this._filterTimeout);
  780.    
  781.     function filterActions()
  782.     {
  783.       var filter = document.getElementById("filter").value;
  784.       if (filter == "") {
  785.         gDownloadActionsWindow.clearFilter();
  786.         return;
  787.       }        
  788.       var view = gDownloadActionsWindow._view;
  789.       view._filterSet = gDownloadActionsWindow._filterActions(filter);
  790.       if (!view._filtered) {
  791.         // Save Display Info for the Non-Filtered mode when we first
  792.         // enter Filtered mode. 
  793.         gDownloadActionsWindow._saveState();
  794.         view._filtered = true;
  795.       }
  796.  
  797.       // Clear the display
  798.       gDownloadActionsWindow._updateRowCount(view._filterSet.length);
  799.       
  800.       // if the view is not empty then select the first item
  801.       if (view.rowCount > 0)
  802.         view.selection.select(0);
  803.  
  804.       document.getElementById("actionsIntro").value = gDownloadActionsWindow._bundle.getString("actionsFiltered");
  805.       document.getElementById("clearFilter").disabled = false;
  806.     }
  807.     window.filterActions = filterActions;
  808.     this._filterTimeout = setTimeout("filterActions();", 500);
  809.   },
  810.   
  811.   onFilterKeyPress: function (aEvent)
  812.   {
  813.     if (aEvent.keyCode == 27) // ESC key
  814.       this.clearFilter();
  815.   },
  816.   
  817.   focusFilterBox: function ()
  818.   { 
  819.     var filter = document.getElementById("filter");
  820.     filter.focus();
  821.     filter.select();
  822.   }  
  823. };
  824.  
  825.